-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Support for no_std #138
Conversation
/// debugging via [`source`] chains. | ||
/// | ||
/// [`source`]: trait.Error.html#method.source | ||
pub trait Error: Debug + Display { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm very hesitant to copy the standard libraries Error
like this, especially the implementations on arbitrary types. One thing I've been negative about is how failure created a new trait and then told everyone that they needed to switch to it to be compatible. This felt like it was a bad "team player" in the broader ecosystem.
I suppose we'd quickly run into coherence problems if we make this a marker trait and provided a blanket implementation?
pub trait Error: Debug + Display {}
impl<T: Debug + Display> Error for T {}
Another avenue is to completely drop Error
and just implement Debug + Display
; any idea what that world might look like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've considered that when I initially tried implementing this, but you quickly lose out on most of snafu's feature such as the ResultExt and OptionExt traits. We'd at least need some trait that we implement in addition to Display and Debug so we can somehow make ResultExt and OptionExt work too. Also not having source chaining is probably pretty bad too. So that's why in my initial prototyping it evolved from not having an Error trait at all to eventually just a Copy of the full thing (although I did consider dropping the deprecated methods).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Error trait introduced here is not really meant to be used anywhere really. In livesplit-core where I've been using this no-std snafu branch the Error trait never is publicly visible to anyone, nor am I even using it directly (it's only indirectly used through ResultExt and OptionExt). It is mostly just a convenience trait to not lose out on any of the features of snafu. So in a way this is not meant to be "a bad team player" that everyone should switch to. It's in a way very similar to the Backtrace shim. Maybe it can be hidden from the documentation even?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually the blanket implementation Error trait could maybe work. I'll see if it causes any problems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although I don't think there even is any harm to having a copy of the Error trait in snafu. You can still treat core as if snafu didn't have an Error trait at all. But if you want to use an Error trait snafu optionally has one available for you to use. And if someone activates the std feature (either directly through a feature of your crate or indirectly), your code automatically uses the std Error trait and there is no "bad team playing" going on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although one problem I can see is that errors from other core crates might not implement an Error trait at all on core, so you can't use ResultExt and co. regardless. That sounds like maybe the bounds on ResultExt and co. should maybe be lifted a bit instead then though. And it's honestly not that bad, a little newtype easily solves the problem and it's much less of a problem than not having an error type in general, which is much more painful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels like we will need to release something and get feedback from people as to the usefulness. I think it's best we call the no-std support / exact implementation experimental.
For example, one thing that concerns me is what happens if one crate using no-std SNAFU exports an error type. Will other crates be able to make use of it, or will they need to wrap it in that newtype?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand what you mean with that. Why would they need to wrap it in a newtype? If the error type is from snafu in a no_std context, then there simply is no Error trait, just like usual. Or are you saying what the story is with two crates using snafu in a no_std context? That should work seamlessly too, unless they are using different snafu versions.
1.18 can't be supported unless we also modify the macro such that it conditionally emits paths to std instead of core (well it can be supported if we put |
1250205
to
ee2bcc1
Compare
Okay, so here's a proposal: We conservatively go for |
This is basically done from my side. The CI server seems to not be responding, but it should turn green eventually and everything is implemented. |
d38ace0
to
5c03a31
Compare
I rebased this onto the latest changes to resolve the conflicts. This is ready for review again :) TL;DR of everything above:
|
compatibility-tests/v1_18/src/lib.rs
Outdated
@@ -1,5 +1,6 @@ | |||
#![cfg(test)] | |||
|
|||
extern crate core; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw you said
it can be supported if we put extern crate core; in the test, but that is a breaking change for everyone using 1.18
I wanted to see which versions would be affected, so I removed this line and built in 1.18, but I didn't get an error; any idea what might have changed or that I might be doing wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's actually Rust 2015 that's affected. The proc macro targets core, but that's not in the prelude in Rust 2015. There is a workaround though that I could implement.
2aff131
to
d73b54d
Compare
Good news, looks like the Error trait is moving into the alloc crate: rust-lang/rust#64017 |
Bad news, the error trait can't move into the alloc crate because of RFC 2504 |
Yeah while not the best news, I still think the approach in this PR works fairly well and can easily be extended to alloc::Error whenever someone figures out how to make it compatible with the backtraces. I think you want the "core::Error" introduced here anyway as a fallback for when you don't even want alloc. |
98a3202
to
86c7bec
Compare
With fehler released, and failure still around, I was wondering if maybe it would be a good idea to move the My hope is that it would help with the interoperability, and get no_std libraries that don't want to buy into a specific error handling crate (snafu/failure...) to still interoperate with them. |
Yeah I was considering that when we had the discussion about the error trait here. There already is a crate, but it seems barely used / maintained. But maybe it can be "revived"? It should definitely have a std feature and auto upgrade to std's Error if it exists, so you automatically get the proper Error trait for the specific use case. |
Do you have a link to said crate? A quick google didn't turn up anything. While discussing this with @leo60228 , we figured such a crate would work like this:
If there's buy-in on the idea, I'd love to get such a crate rolling. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great, and I'm down for merging it once the one question is answered. Thanks for your patience!
core::fmt::Error, // 1.11 | ||
core::cell::BorrowMutError, // 1.13 | ||
core::cell::BorrowError, // 1.13 | ||
core::char::ParseCharError // 1.20 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we bumped our minimum version to 1.31, are there any errors missing from this list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not that I'm aware of. When I created the PR these were all the Error impls in std. These used to be three macro calls where one had the rust_1_30 feature check, but I condensed that into the unconditional macro call, so I don't think I missed any (other than potential ones in 1.38+ or so).
However what is missing is all the alloc based error types. We'd need an alloc feature for those.
@roblabla I think that's a great idea! I'd be much happier knowing that we weren't making some completely custom trait that was tied to this crate. Ideally, some magical solution would come from libcore, but until that happens, a shared community crate seems like a great step. Since this PR is likely to be resolved before that crate can completely be usable for our cases, would you mind opening a new issue to track the idea? |
This brings no_std support to SNAFU. It now has a `std` feature which is activated by default. To make no_std support as frictionless as possible, SNAFU now reexports the `std::error::Error` trait as `snafu::Error` when the feature is activated and defines its own API compatible trait instead when it's disabled. In order to not commit to having a publicly visible copy of the `Error` trait in SNAFU, hiding it from the documentation allows for SNAFU to still support all of its features, but the user never gets to use the trait. This way SNAFU can switch out the trait at any point with `core::error::Error` if that becomes a thing. Alternatively the trait here can also be made visible at some point. Both of these possibilities are not breaking, so the conservative approach with `doc(hidden)` allows for the smoothest experience going forward. Resolves shepmaster#85
- rustup target add thumbv6m-none-eabi | ||
primary_test_script: | ||
- rustc --version | ||
- cargo build --no-default-features --target thumbv6m-none-eabi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Completely unrelated, but thanks for showing me how to actually make some kind of test for a no-std crate. I had some really nasty hacks to try and do this before.
Thanks! |
This brings no_std support to snafu. It now has a
std
feature which is activated by default. To make no_std support as frictionless as possible, snafu now internally either uses thestd::error::Error
trait when the feature is activated and defines its own API compatible trait instead when it's disabled, but it is never exposed publicly for now.Resolves #85